'''
@author devdoer@gmail.com
'''
from  sgmllib import SGMLParser,SGMLParseError 
import re

class Error:
	def __init__(self,str):
		self.str=str
	def __str__(self):
		return self.str
def depth_first_walk(node,func,arg):
		if node.tag=='text':
			func(node,arg,True)
		else:
			func(node,arg,True)
			for c in node.childs:
				depth_first_walk(c,func,arg)
			func(node,arg,False)
class Node:
	def __init__(self):
		self.tag=''
		self.parent=None

	def __to_str(self,node,strs,first):
		if node.tag=='text':
			strs.append(node.content)
		else:
			if first:
				strs.append('<'+node.tag)
				for attr,val in node.attrs.items():
					strs.append(' '+attr+'='+'"'+val+'"')
				strs.append('>')
			else:
				strs.append('</'+node.tag+'>')

	def to_str(self):
		strs=[]
		depth_first_walk(self,self.__to_str,strs)
		return ''.join(strs)
	def all_parents(self):
		ps=[]
		p=self.parent
		while p:
			ps.append(p)
			p=p.parent
		return ps	

class TextNode(Node):
	def __init__(self):
		Node.__init__(self)
		self.tag='text'
		self.content=''
class TagNode(Node):
	def __init__(self,tag,attrs={}):
		Node.__init__(self)
		self.tag=tag
		self.attrs=attrs
		self.childs=[]
	def get_attribute(self,name):
		return self.attrs[name]
	def first_child(self):
		try:
			return self.childs[0]
		except IndexError:
			return None
	def find_by_tag_name(self,tagName):
		l=[]
		#width first walk
		toCheckNodes=[]
		toCheckNodes.extend(self.childs)
		while True:
			try:
				n=toCheckNodes.pop(0)
			except IndexError:
				break
			if n.tag=='text':
				continue
			if n.tag==tagName:
				l.append(n)
			else:
				#check its childs	
				toCheckNodes.extend(n.childs)
		return l
class Doc(TagNode):
	def __init__(self):
		TagNode.__init__(self,'xml')
		#self.tag='xml'

class DomBuilder(SGMLParser):
	def __init__(self):
		self.__doc=Doc()
		self.__curTagNode=self.__doc
		self.__curNode=self.__curTagNode
		SGMLParser.__init__(self)

	def parse(self,data):
		self.feed(data)
		return self.__doc
	def feed(self,data):
		SGMLParser.feed(self,data)
		self.close()



	def unknown_starttag(self,tag,attrs):
		m={}
		for attr,val in attrs:
			m[attr]=val
		n=TagNode(tag,m)
		n.parent=self.__curTagNode
		self.__curTagNode.childs.append(n)
		self.__curTagNode=n
		self.__curNode=n
			


	def handle_comment(self,data):
		self.handle_data(data)
				
	def handle_data(self,data):
		if self.__curNode.tag=='text':
		#if current node is a text node
			self.__curNode.content+=data
		else:
			n=TextNode()
			n.content=data
			n.parent=self.__curTagNode
			self.__curTagNode.childs.append(n)
			self.__curNode=n
	def unknown_endtag(self,tag):
		cur=self.__curTagNode
		if cur.tag!=tag:
			raise Error('unbalanced:</'+tag+'>')
		#back to parent node 
		self.__curTagNode=cur.parent
		self.__curNode=cur.parent

